package vip.meeet.generate;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ParseResult;
import com.github.javaparser.ast.CompilationUnit;
import com.github.javaparser.ast.NodeList;
import com.github.javaparser.ast.body.BodyDeclaration;
import com.github.javaparser.ast.body.TypeDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import vip.meeet.elasticsearch.EsHelper;
import vip.meeet.elasticsearch.common.ESConstant;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;

/**
 * 根据源码生成 ES mapping json文件
 */
public final class BeanMappingGenerator {

    /**
     * java 类型到ES类型映射
     */
    private static final Map<String, String> JE_TYPE_MAP = new HashMap<>();

    static {
//        JE_TYPE_MAP.put("string", "text");
        JE_TYPE_MAP.put("string","keyword");
        JE_TYPE_MAP.put("byte", "byte");
        JE_TYPE_MAP.put("short", "short");
        JE_TYPE_MAP.put("int", "integer");
        JE_TYPE_MAP.put("integer", "integer");
        JE_TYPE_MAP.put("long", "long");
        JE_TYPE_MAP.put("float", "float");
        JE_TYPE_MAP.put("doule", "doule");
        JE_TYPE_MAP.put("boolean", "boolean");
        JE_TYPE_MAP.put("date", "date");
        JE_TYPE_MAP.put("bigdecimal", "doule");
    }

    /**
     * 通过Java源文件注释生成字段文档
     *
     * @param srcFile Java源文件绝对路径
     * @param destDir 生成的文件存放目录
     * @throws IOException
     */
    public static void getMapping(String srcFile, String destDir) throws IOException {
        Path srcPath = Paths.get(srcFile);
        JavaParser javaParser = new JavaParser();
        ParseResult<CompilationUnit> parseResult = javaParser.parse(srcPath);
        Optional<CompilationUnit> result = parseResult.getResult();
        result.ifPresent(new Consumer<CompilationUnit>() {
            @Override
            public void accept(CompilationUnit compilationUnit) {
                NodeList<TypeDeclaration<?>> types = compilationUnit.getTypes();
                for (TypeDeclaration<?> type : types) {
                    String nameAsString = type.getNameAsString();
                    Path destPath = Paths.get(destDir + File.separatorChar + nameAsString + ".json");
                    JSONObject json = new JSONObject();
                    JSONObject mappings = new JSONObject();
                    JSONObject properties = new JSONObject();
                    BufferedWriter bufferedWriter;
                    try {
                        bufferedWriter = Files.newBufferedWriter(destPath);
                        NodeList<BodyDeclaration<?>> members = type.getMembers();
                        for (BodyDeclaration<?> member : members) {
                            member.toFieldDeclaration().ifPresent(field -> {
                                for (VariableDeclarator variable : field.getVariables()) {
                                    JSONObject fieldObj = new JSONObject();
                                    String typeName = variable.getTypeAsString();
                                    String name = variable.getNameAsString();
                                    String esType = JE_TYPE_MAP.get(typeName.toLowerCase());
                                    fieldObj.put(ESConstant.type, esType);
                                    properties.put(name,fieldObj);
                                }
                            });
                        }
                        mappings.put(ESConstant.properties,properties);
                        mappings.put(ESConstant.dynamic,false);
                        json.put(ESConstant.mappings,mappings);
                        json.put(ESConstant.settings, EsHelper.getDefaultSettings());
                        bufferedWriter.write(json.toString(SerializerFeature.PrettyFormat));
                        bufferedWriter.flush();
                        bufferedWriter.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }
}
